load("@rules_rust//cargo:defs.bzl", "cargo_build_script")
load("@rules_rust//rust:defs.bzl", "rust_library", "rust_test")
load("//bazel:canbench.bzl", "rust_canbench")
load("//bazel:canisters.bzl", "rust_canister")
load("//bazel:defs.bzl", "rust_test_suite_with_extra_srcs")
load("//bazel:prost.bzl", "generated_files_check")
load("//rs/nervous_system/patch_canister_did:defs.bzl", "canister_test_did")
load(":feature_flags.bzl", "test_with_tla")

package(default_visibility = ["//rs/nervous_system:default_visibility"])

exports_files(
    # Notice that governance.proto is NOT included. This is very intentional. We
    # only use that for storing things to stable memory, not for communication
    # with clients.
    [
        "canister/governance.did",
        "canister/governance_test.did.patch",
    ],
    visibility = [
        "//visibility:public",
    ],
)

canister_test_did(
    name = "test_did",
    canister_did = "canister/governance.did",
    canister_test_did_patch = "canister/governance_test.did.patch",
    output_path = "canister/governance_test.did",
)

# Allows temporarily disabling TLA checks from the command line;
# just pass `--define tla_disabled=true` to your Bazel command
# See feature_flags.bzl for how to disable TLA checks permanently
# (in the CI)
config_setting(
    name = "tla_disabled",
    values = {
        "define": "tla_disabled=true",
    },
)

filegroup(
    name = "protos",
    srcs = glob(["proto/**/*.proto"]),
)

# See rs/nervous_system/feature_test.md
DEPENDENCIES = [
    # Keep sorted.
    "//packages/ic-dummy-getrandom-for-wasm",
    "//packages/ic-http-types",
    "//packages/icrc-ledger-types:icrc_ledger_types",
    "//rs/crypto/sha2",
    "//rs/ledger_suite/common/ledger_core",
    "//rs/ledger_suite/icp:icp_ledger",
    "//rs/limits",
    "//rs/nervous_system/canisters",
    "//rs/nervous_system/clients",
    "//rs/nervous_system/common",
    "//rs/nervous_system/common/validation",
    "//rs/nervous_system/governance",
    "//rs/nervous_system/linear_map",
    "//rs/nervous_system/lock",
    "//rs/nervous_system/long_message",
    "//rs/nervous_system/neurons_fund",
    "//rs/nervous_system/proto",
    "//rs/nervous_system/rate_limits",
    "//rs/nervous_system/root",
    "//rs/nervous_system/runtime",
    "//rs/nervous_system/temporary",
    "//rs/nervous_system/time_helpers",
    "//rs/nervous_system/timer_task",
    "//rs/nervous_system/timers",
    "//rs/nns/cmc",
    "//rs/nns/common",
    "//rs/nns/constants",
    "//rs/nns/governance/api",
    "//rs/nns/governance/init",
    "//rs/nns/gtc_accounts",
    "//rs/nns/handlers/root/interface",
    "//rs/nns/sns-wasm",
    "//rs/node_rewards/canister/api",
    "//rs/protobuf",
    "//rs/registry/canister",
    "//rs/registry/subnet_type",
    "//rs/rust_canisters/on_wire",
    "//rs/sns/init",
    "//rs/sns/root",
    "//rs/sns/swap",
    "//rs/types/base_types",
    "//rs/types/management_canister_types",
    "//rs/types/types",
    "//rs/utils",
    "@crate_index//:build-info",
    "@crate_index//:bytes",
    "@crate_index//:candid",
    "@crate_index//:candid_parser",
    "@crate_index//:chrono_canisters",
    "@crate_index//:comparable",
    "@crate_index//:dyn-clone",
    "@crate_index//:futures",
    "@crate_index//:ic-cdk",
    "@crate_index//:ic-cdk-timers",
    "@crate_index//:ic-metrics-encoder",
    "@crate_index//:ic-stable-structures",
    "@crate_index//:itertools",
    "@crate_index//:lazy_static",
    "@crate_index//:maplit",
    "@crate_index//:mockall",
    "@crate_index//:num-traits",
    "@crate_index//:pretty_assertions",
    "@crate_index//:prost",
    "@crate_index//:rand",
    "@crate_index//:rand_chacha",
    "@crate_index//:rust_decimal",
    "@crate_index//:serde",
    "@crate_index//:serde_bytes",
    "@crate_index//:serde_json",
    "@crate_index//:strum",
] + select({
    "@rules_rust//rust/platform:wasm32-unknown-unknown": [],
    "//conditions:default": [
        # Keep sorted.
        "//rs/nervous_system/common/test_keys",
        "@crate_index//:csv",
    ],
})

MACRO_DEPENDENCIES = [
    # Keep sorted.
    "//rs/nervous_system/common/build_metadata",
    "@crate_index//:async-trait",
    "@crate_index//:rust_decimal_macros",
    "@crate_index//:strum_macros",
]

BUILD_DEPENDENCIES = [
    # Keep sorted.
    "@crate_index//:build-info-build",
]

DEV_DEPENDENCIES = [
    # Keep sorted.
    "//rs/config",
    "//rs/nervous_system/common/test_utils",
    "//rs/nns/governance/protobuf_generator:lib",
    "//rs/sns/swap/protobuf_generator:lib",
    "//rs/test_utilities/compare_dirs",
    "//rs/tla_instrumentation",
    "//rs/tla_instrumentation:local_key",
    "@crate_index//:prometheus-parse",
    "@crate_index//:proptest",
    "@crate_index//:tempfile",
    "@crate_index//:tokio",
    "@crate_index//:tokio-test",
] + select({
    "@rules_rust//rust/platform:wasm32-unknown-unknown": [],
    "//conditions:default": [
        "@crate_index//:assert_matches",
    ],
})

MACRO_DEV_DEPENDENCIES = ["//rs/tla_instrumentation:proc_macros"]

ALIASES = {}

LIB_SRCS = glob(
    ["src/**/*.rs"],
    exclude = [
        "**/*tests.rs",
        "**/tests/**",
    ],
)

cargo_build_script(
    name = "build_script",
    srcs = ["build.rs"],
    aliases = ALIASES,
    data = [],  # build script data (e.g. template files) goes here
    version = "0.9.0",
    deps = BUILD_DEPENDENCIES,
)

rust_library(
    name = "governance",
    srcs = LIB_SRCS,
    aliases = ALIASES,
    crate_name = "ic_nns_governance",
    proc_macro_deps = MACRO_DEPENDENCIES,
    version = "0.9.0",
    deps = DEPENDENCIES + [
        ":build_script",
    ],
)

rust_library(
    name = "governance--test_feature",
    srcs = LIB_SRCS,
    aliases = ALIASES,
    crate_features = test_with_tla(),
    crate_name = "ic_nns_governance",
    proc_macro_deps = MACRO_DEPENDENCIES + [
        "//rs/tla_instrumentation:proc_macros",
    ],
    version = "0.9.0",
    deps = DEPENDENCIES + [
        ":build_script",
        "//rs/tla_instrumentation",
        "//rs/tla_instrumentation:local_key",
    ],
)

rust_library(
    name = "governance--canbench_feature",
    srcs = LIB_SRCS,
    aliases = ALIASES,
    crate_features = ["canbench-rs"],
    crate_name = "ic_nns_governance",
    proc_macro_deps = MACRO_DEPENDENCIES,
    version = "0.9.0",
    visibility = ["//visibility:private"],
    deps = DEPENDENCIES + [
        "@crate_index//:canbench-rs",
    ],
)

# Usage:
# bazel run //rs/nns/governance:governance-canbench for benchmarking
# bazel run //rs/nns/governance:governance-canbench_update for updating the results file.
# Currently, updating the results file is not automated, and there are no tests to avoid
# regression. For now, we can use it as an example for benchmarking as part of an
# investigation of potential performance issues, or when we make a change that can affect
# the performance measured in this benchmark (currently the benchmark only measures adding a
# neuron).
rust_canbench(
    name = "governance-canbench",
    srcs = ["canbench/main.rs"],
    add_test = True,
    noise_threshold = 5.0,
    # For some reason, the NNS Governance benchmarks are sensitive to the optimization level.
    # We would like to figure out why and fix it, but for now, we are reducing the optimization
    # level so that tests against the optimization level can be added.
    opt = "s",
    results_file = "canbench/canbench_results.yml",
    deps = [
        # Keep sorted.
        ":governance--canbench_feature",
    ],
)

# Used for benchmarking compilation/instrumentation/execution changes in the
# embedders crate.
rust_canister(
    name = "governance-bench-canister",
    srcs = ["canbench/main.rs"],
    aliases = ALIASES,
    compile_data = ["canbench/bench.did"],
    proc_macro_deps = MACRO_DEPENDENCIES,
    service_file = ":canbench/bench.did",
    visibility = ["//visibility:public"],
    deps = [
        ":governance--canbench_feature",
    ],
)

rust_canister(
    name = "governance-canister",
    srcs = ["canister/canister.rs"],
    aliases = ALIASES,
    compile_data = ["canister/governance.did"],
    proc_macro_deps = MACRO_DEPENDENCIES,
    service_file = ":canister/governance.did",
    visibility = ["//visibility:public"],
    deps = DEPENDENCIES + [
        ":build_script",
        ":governance",
    ],
)

rust_canister(
    name = "governance-canister-test",
    testonly = True,
    srcs = [
        "canister/canister.rs",
        "canister/tla_ledger.rs",
    ],
    aliases = ALIASES,
    compile_data = [":test_did"],
    crate_features = test_with_tla(),
    crate_root = "canister/canister.rs",
    did_check = False,  # we don't check in the did so can't meaningfully check
    proc_macro_deps = MACRO_DEPENDENCIES + [
        "//rs/tla_instrumentation:proc_macros",
    ],
    service_file = ":test_did",
    visibility = ["//visibility:public"],
    deps = DEPENDENCIES + [
        ":build_script",
        ":governance--test_feature",
        "//rs/tla_instrumentation",
    ],
)

generated_files_check(
    name = "check_generated_files",
    srcs = ["tests/check_generated_files.rs"],
    data = glob(["src/gen/**/*.rs"]) + [
        ":protos",
        "//rs/ledger_suite/icp:protos",
        "//rs/nervous_system/proto:protos",
        "//rs/nns/common:protos",
        "//rs/sns/root:protos",
        "//rs/sns/swap:protos",
        "//rs/types/base_types:protos",
    ],
    manifest_dir = "rs/nns/governance",
    deps = [
        # Keep sorted.
        "//rs/nns/governance/protobuf_generator:lib",
        "//rs/test_utilities/compare_dirs",
        "@crate_index//:tempfile",
    ],
)

rust_test(
    name = "canister_unit_test",
    srcs = glob(["canister/**/*.rs"]),
    compile_data = [":canister/governance.did"],
    crate_root = "canister/canister.rs",
    proc_macro_deps = MACRO_DEPENDENCIES,
    deps = DEPENDENCIES + DEV_DEPENDENCIES + [
        ":build_script",
        ":governance",
    ],
)

rust_test(
    name = "canister_test_unit_test",
    srcs = glob(["canister/**/*.rs"]),
    compile_data = [":canister/governance_test.did"],
    crate_features = test_with_tla(),
    crate_root = "canister/canister.rs",
    proc_macro_deps = MACRO_DEPENDENCIES + MACRO_DEV_DEPENDENCIES,
    deps = DEPENDENCIES + DEV_DEPENDENCIES + [
        ":build_script",
        ":governance--test_feature",
    ],
)

rust_test(
    name = "governance_test",
    srcs = glob(["src/**/*.rs"]),
    aliases = ALIASES,
    proc_macro_deps = MACRO_DEPENDENCIES + MACRO_DEV_DEPENDENCIES,
    deps = DEPENDENCIES + DEV_DEPENDENCIES + [
        ":build_script",
    ],
)

rust_test(
    name = "governance_test-test_feature",
    srcs = glob(["src/**/*.rs"]),
    aliases = ALIASES,
    crate_features = test_with_tla(),
    proc_macro_deps = MACRO_DEPENDENCIES + MACRO_DEV_DEPENDENCIES,
    deps = DEPENDENCIES + DEV_DEPENDENCIES + [
        ":build_script",
    ],
)

# all TLA models
# NOTE: the test runner assumes unique basenames
filegroup(
    name = "tla_models",
    srcs = glob(["tla/*.tla"]),
)

rust_test_suite_with_extra_srcs(
    name = "governance_integration_test",
    # the test sometimes times out on CI with default timeout
    # of "moderate" (5 minutes) - 2025-07-04
    timeout = "long",
    srcs = glob(
        ["tests/*.rs"],
        exclude = [
            # fake.rs is a module dependency, not a test
            "tests/fake.rs",
            # check generated files is handled in the generated_files_check rule above
            "tests/check_generated_files.rs",
        ],
    ),
    aliases = ALIASES,
    crate_features = test_with_tla(),
    data = [
        "tests/neurons.csv",
        ":tla_models",
        "@bazel_tools//tools/jdk:current_java_runtime",
        "@tla_apalache//:bin/apalache-mc",
    ],
    env = {
        "NEURON_CSV_PATH": "rs/nns/governance/tests/neurons.csv",
        "JAVABASE": "$(JAVABASE)",
        "TLA_APALACHE_BIN": "$(rootpath @tla_apalache//:bin/apalache-mc)",
        "TLA_MODULES": "$(locations :tla_models)",
    },
    extra_srcs = glob([
        "tests/*/*.rs",
    ]) + ["tests/fake.rs"],
    flaky = True,  # the governance test times out in over 2% of runs
    proc_macro_deps = MACRO_DEPENDENCIES + MACRO_DEV_DEPENDENCIES,
    toolchains = ["@bazel_tools//tools/jdk:current_java_runtime"],
    deps = [":governance--test_feature"] + DEPENDENCIES + DEV_DEPENDENCIES + [
        ":build_script",
    ],
)
